package com.ruoyi.bill.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.lock.LockInfo;
import com.baomidou.lock.LockTemplate;
import com.baomidou.lock.executor.RedissonLockExecutor;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.ruoyi.bill.domain.BillCustomInvest;
import com.ruoyi.bill.domain.BillFinance;
import com.ruoyi.bill.domain.bo.BillCustomInvestBo;
import com.ruoyi.bill.domain.vo.BillCustomInvestVo;
import com.ruoyi.bill.domain.vo.BillFinanceVo;
import com.ruoyi.bill.mapper.BillCustomInvestMapper;
import com.ruoyi.bill.service.IBillCustomInvestService;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.core.domain.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.bill.domain.bo.BillPortBo;
import com.ruoyi.bill.domain.vo.BillPortVo;
import com.ruoyi.bill.domain.BillPort;
import com.ruoyi.bill.mapper.BillPortMapper;
import com.ruoyi.bill.service.IBillPortService;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 端口台账Service业务层处理
 *
 * @author linziheng
 * @date 2024-02-29
 */
@RequiredArgsConstructor
@Service
public class BillPortServiceImpl implements IBillPortService {

    private final BillPortMapper baseMapper;
    private final BillCustomInvestMapper billCustomInvestMapper;
    @Autowired
    private LockTemplate lockTemplate;

    @Override
    public Map getTodayTotal(String now){

        double port = baseMapper.getTodayTotal(now);
        double cus = billCustomInvestMapper.getTodayTotal(now);
        Map map = new HashMap();
        map.put("port", port);
        map.put("cus", cus);

        return map;
    }


    @Override
    public List<String> accountBelongList(){
        return baseMapper.accountBelongList();
    }
    /**
     * 查询端口台账
     */
    @Override
    public BillPortVo queryById(Long id){
        return baseMapper.selectVoById(id);
    }

    /**
     * 查询端口台账列表
     */
    @Override
    public TableDataInfo<BillPortVo> queryPageList(BillPortBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<BillPort> lqw = buildQueryWrapper(bo);
        Page<BillPortVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);

        TableDataInfo<BillPortVo> tableDataInfo = TableDataInfo.build(result);
        tableDataInfo.setCurrPort(baseMapper.currPort(bo));
        return tableDataInfo;
    }

    /**
     * 查询端口台账列表
     */
    @Override
    public List<BillPortVo> queryList(BillPortBo bo) {
        LambdaQueryWrapper<BillPort> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<BillPort> buildQueryWrapper(BillPortBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<BillPort> lqw = Wrappers.lambdaQuery();
        if("1".equals(bo.getFinanceType())){
            lqw.eq(StringUtils.isNotBlank(bo.getFinanceType()), BillPort::getFinanceType, bo.getFinanceType())
                .or().isNull(BillPort::getFinanceType);
        }else{
            lqw.eq(StringUtils.isNotBlank(bo.getFinanceType()), BillPort::getFinanceType, bo.getFinanceType());
        }
        if("1".equals(bo.getCheckType())){
            lqw.eq(StringUtils.isNotBlank(bo.getCheckType()), BillPort::getCheckType, bo.getCheckType())
                .or().isNull(BillPort::getCheckType);
        }else{
            lqw.eq(StringUtils.isNotBlank(bo.getCheckType()), BillPort::getCheckType, bo.getCheckType());
        }
        lqw.eq(StringUtils.isNotBlank(bo.getAccountId()), BillPort::getAccountId, bo.getAccountId());
        lqw.like(StringUtils.isNotBlank(bo.getAccountName()), BillPort::getAccountName, bo.getAccountName());
        lqw.like(StringUtils.isNotBlank(bo.getCompanyName()), BillPort::getCompanyName, bo.getCompanyName());
        lqw.eq(StringUtils.isNotBlank(bo.getReconciliation()), BillPort::getReconciliation, bo.getReconciliation());
        lqw.eq(StringUtils.isNotBlank(bo.getAccountBelong()), BillPort::getAccountBelong, bo.getAccountBelong());

        lqw.like(StringUtils.isNotBlank(bo.getRemark()), BillPort::getRemark, bo.getRemark());
        lqw.between(params.get("beginUpTime") != null && params.get("endUpTime") != null,
            BillPort::getUpTime ,params.get("beginUpTime"), params.get("endUpTime"));
        lqw.between(params.get("beginAccountTime") != null && params.get("endAccountTime") != null,
            BillPort::getAccountTime ,params.get("beginAccountTime"), params.get("endAccountTime"));
        lqw.like(StringUtils.isNotBlank(bo.getIndustryType()), BillPort::getIndustryType, bo.getIndustryType());
        lqw.like(StringUtils.isNotBlank(bo.getSignatory()), BillPort::getSignatory, bo.getSignatory());
        lqw.like(StringUtils.isNotBlank(bo.getAccountType()), BillPort::getAccountType, bo.getAccountType());
        lqw.like(StringUtils.isNotBlank(bo.getPolicyType()), BillPort::getPolicyType, bo.getPolicyType());
        lqw.like(StringUtils.isNotBlank(bo.getRecipient()), BillPort::getRecipient, bo.getRecipient());
        lqw.orderByDesc(BillPort::getAccountTime);
        lqw.orderByDesc(BillPort::getCreateTime);
        lqw.orderByDesc(BillPort::getIndexXn);
        return lqw;
    }

    /**
     * 新增端口台账
     */
    @Override
    public Boolean insertByBo(BillPortBo bo) {
        boolean flag = false;
        BillPort add = BeanUtil.toBean(bo, BillPort.class);
        validEntityBeforeSave(add);
//        查询客户台账信息 同账户id 同广告币 未匹配状态数据
        BillCustomInvestBo billCustomInvestBo = new BillCustomInvestBo();
        billCustomInvestBo.setAccountId(bo.getAccountId());
        billCustomInvestBo.setCurrency(bo.getCurrency());
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
        // 使用SimpleDateFormat的format方法将Date对象转换为字符串
        String formattedDate = sdf.format(bo.getAccountTime());
        billCustomInvestBo.setAccountTimeTemp(formattedDate);
        add.setCheckType("1");
       // List<BillCustomInvest> list = billCustomInvestMapper.getNoList(billCustomInvestBo);
//        if(!list.isEmpty()){
//            BillCustomInvest vo = list.get(0);
//            add.setPpId(vo.getId());
//            add.setCheckType("0");
//            vo.setCheckType("0");
//            billCustomInvestMapper.updateById(vo);
//        }
        final LockInfo lockInfo = lockTemplate.lock("port", 30000L, 5000L, RedissonLockExecutor.class);
        if (null == lockInfo) {
            throw new RuntimeException("业务处理中,请稍后再试");
        }
        try {
            add = countBillPort(add);
            try {
                Thread.sleep(1001);
            } catch (InterruptedException e) {
                //
            }
        flag = baseMapper.insert(add) > 0;

        } finally {
            //释放锁
            lockTemplate.releaseLock(lockInfo);
        }

        if (flag) {
            bo.setId(add.getId());
        }
        return flag;
    }

    /**
     * 补录
     */
    @Override
    public Boolean recordByBo(BillPortBo bo) {
        BillPort billPort = new BillPort();

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String formattedDate = sdf.format(bo.getAccountTime());
        bo.setAccountTime2(formattedDate);
        List<BillPort> list = baseMapper.recordListDesc(bo);
        if(!list.isEmpty()){
            // 有历史记录
            billPort = list.get(0);
            if(billPort.getBalance()!=null){
                bo.setBalance(billPort.getBalance().add(bo.getActualCash()).subtract(bo.getInCash()));
            }else{
                // 第一条记录
                bo.setBalance(new BigDecimal(0).add(bo.getActualCash()).subtract(bo.getInCash()));
            }
        }else{
            // 第一条记录
            bo.setBalance(new BigDecimal(0).add(bo.getActualCash()).subtract(bo.getInCash()));
        }
        // 查询端口台账，相同账号归属 升序列表
        List<BillPort> uplist = baseMapper.recordListBl(bo);
        // 处理历史数据
        for (int i = 0; i < uplist.size(); i++) {
            if(i==0){
                // 第一条记录
                uplist.get(i).setBalance(bo.getBalance().add(uplist.get(i).getActualCash()).subtract(uplist.get(i).getInCash()));
            }else{
                uplist.get(i).setBalance(uplist.get(i-1).getBalance().add(uplist.get(i).getActualCash()).subtract(uplist.get(i).getInCash()));
            }
        }
        BillPort add = BeanUtil.toBean(bo, BillPort.class);
        uplist.add(add);
        return baseMapper.insertOrUpdateBatch(uplist);
    }
    /**
     * 修改端口台账
     */
    @Override
    public Boolean updateByBo(BillPortBo bo) {
        deleteWithValidByIds(Collections.singleton(bo.getId()), true);
        return recordByBo(bo);
    }

    public BillPort countBillPort(BillPort bo){

        BillPortBo billPortBo = new BillPortBo();
        billPortBo.setAccountBelong(bo.getAccountBelong());
        BillPort billPort = new BillPort();
        List<BillPort> list = baseMapper.selectListByAccountBelong(bo.getAccountBelong(),bo.getSignatory());
        if(!list.isEmpty()){
            //获取最新一条记录
            billPort  = list.get(0);
            if(billPort.getBalance()!=null){
                bo.setBalance(billPort.getBalance().add(bo.getActualCash()).subtract(bo.getInCash()));
            }else{
                // 第一条记录
                bo.setBalance(new BigDecimal(0).add(bo.getActualCash()).subtract(bo.getInCash()));
            }
        }else{
//            新纪录
            bo.setBalance(new BigDecimal(0).add(bo.getActualCash()).subtract(bo.getInCash()));
        }
        return bo;
    }
    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(BillPort entity){
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 批量删除端口台账
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        boolean flag = true;
        for (Long id : ids) {
            BillPortVo vo = baseMapper.selectVoById(id);
            if(!Objects.isNull(vo)){
                BillPortBo bo = BeanUtil.toBean(vo, BillPortBo.class);
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
                String formattedDate = sdf.format(bo.getAccountTime());
                bo.setAccountTime2(formattedDate);
//                SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//                bo.setCreateTime2(sdf2.format(vo.getCreateTime()));

                // 查询端口台账，相同账号归属 升序列表
                List<BillPort> uplist = baseMapper.recordListNoThis(bo);
                //需要判断list是否存在到账时间相同创建时间在当前数据之前的
                List<BillCustomInvest> downList = baseMapper.previous(bo);
                // 第一条记录

                // 处理历史数据
                for (int i = 0; i < uplist.size(); i++) {
                    if(i==0){
                        // 第一条记录

                        if(downList.size()>0) {
                            //大于0 获取上一条记录
                            bo = BeanUtil.toBean(downList.get(0), BillPortBo.class);
                            uplist.get(i).setBalance(bo.getBalance().add(uplist.get(i).getActualCash()).subtract(uplist.get(i).getInCash()));
                        }else{
                            uplist.get(i).setBalance(new BigDecimal(0).add(uplist.get(i).getActualCash()).subtract(uplist.get(i).getInCash()));

                        }

                    }else{
                        uplist.get(i).setBalance(uplist.get(i-1).getBalance().add(uplist.get(i).getActualCash()).subtract(uplist.get(i).getInCash()));
                    }
                }
                baseMapper.deleteById(id);
                 baseMapper.insertOrUpdateBatch(uplist);

            }

        }
        return flag;
    }

    @Override
    @Transactional
    public R matching() {
        List<BillCustomInvest> billCustomInvest = billCustomInvestMapper.getNoList();
        List<BillPort> billPort = baseMapper.getNoList();

        if(billPort.isEmpty() || billCustomInvest.isEmpty()){
            return R.fail("未查到需要匹配的数据");
        }
        Map<String, Double> billCustomInvestMap = billCustomInvest.stream().collect(Collectors.groupingBy(BillCustomInvest::getTemp,Collectors.summingDouble(BillCustomInvest::getDoubleNum)));
        Map<String, Double> billPortMap = billPort.stream().collect(Collectors.groupingBy(BillPort::getTemp,Collectors.summingDouble(BillPort::getDoubleNum)));

        for (String key : billCustomInvestMap.keySet()) {
            Double value = billPortMap.get(key);
            if(Objects.equals(value, billCustomInvestMap.get(key))){
                //匹配成功
                baseMapper.update(null,
                    new LambdaUpdateWrapper<BillPort>()
                        .eq(BillPort::getAccountId, key.split("~")[0])
                        .eq(BillPort::getAccountTime, key.split("~")[1])
                        .set(BillPort::getCheckType, "0"));
                billCustomInvestMapper.update(null,
                    new LambdaUpdateWrapper<BillCustomInvest>()
                        .eq(BillCustomInvest::getAccountId, key.split("~")[0])
                        .eq(BillCustomInvest::getAccountTime, key.split("~")[1])
                        .set(BillCustomInvest::getCheckType, "0"));
            }

        }
        // 更新结束后 将所有空白数据 设置为未匹配
        billCustomInvestMapper.updateNo();
        baseMapper.updateNo();
        return R.ok();
    }


    @Override
    public void transfer() {
       List<BillPort> billPorts = baseMapper.transfer();
        List<BillPort> newBillPorts = new ArrayList<>();
        billPorts.forEach(item ->{
            if(!item.getSignatory().equals(item.getOldSignatory())){
                newBillPorts.add(item);
            }
        });
        baseMapper.updateBatchById(newBillPorts);
    }

}
